from mysite.config.django_setup import *
from core.object import TradeData
from .models import Strategy, StrategyResult, Account, SchedulerStatus,\
      TaskStatus, AccountBroker,TradeRecord
from pandas import Series
from django.db import transaction
import logging
from lqu import get_current_price
from datetime import datetime as dt
logger = logging.getLogger('fucker')


class StrategyResultManagement:

    @staticmethod
    def update_strategy_result(strategy_name, strategy_result, ts):
        strategy = Strategy.objects.get(name=strategy_name)
        sr = StrategyResult.objects.filter(strategy=strategy)
        sr.filter(latest=False).delete()
        sr.update(latest=False)

        new_sr = [StrategyResult(strategy=strategy, symbol=symbol, percent=pct, ts=ts) for symbol, pct in strategy_result.items()]
        sr.bulk_create(new_sr)

    @staticmethod
    def get_all_used_symbols():
        return StrategyResult.objects.values_list('symbol', flat=True).distinct()

    @staticmethod
    def get_latest_strategy_result(strategy_name):
        strategy = Strategy.objects.get(name=strategy_name)
        return strategy.get_latest_result()

    @staticmethod
    def get_all_strategy_names():
        return Strategy.objects.values_list('name', flat=True).distinct()


class AccountManagement:
    @staticmethod
    def sync_all_positions(account_name, broker_pos: Series):
        with transaction.atomic():
            account = Account.objects.select_for_update().get(name=account_name)
            logger.info(f'account_name ::{account_name}')
            account_pos = Series(dict(account.position_set.values_list('symbol', 'volume')))
            change_pos = broker_pos.sub(account_pos, fill_value=0)
            change_pos = change_pos[change_pos != 0]
            logger.info(f'change_pos ::{change_pos}')
            if len(change_pos) > 0:
                for symbol, volume in change_pos.items():
                    price = get_current_price([symbol])[symbol]
                    account.long(symbol, volume, price)
                return change_pos
            else:
                return None

    @staticmethod
    def check_position(account_name, broker_pos: Series):
        """
        return True if local pos == broker pos
        :param account_name:
        :param broker_pos:
        :return:
        """
        account = Account.objects.get(name=account_name)
        account_pos = Series(dict(account.position_set.values_list('symbol', 'volume')))
        change_pos = broker_pos.sub(account_pos, fill_value=0)
        change_pos = change_pos[change_pos != 0]
        return len(change_pos) == 0

    @staticmethod
    def get_account_by_name(account_name):
        return Account.objects.get(name=account_name)

    @staticmethod
    def adjust_nav(account_name, adjust_to_nav):
        with transaction.atomic():
            account = Account.objects.select_for_update().get(name=account_name)
            account.cash += (adjust_to_nav - account.nav)
            account.save()

    @staticmethod
    def update_broker_info(account_name, balance, available):
        account = Account.objects.get(name=account_name)
        broker, created = AccountBroker.objects.get_or_create(account=account)
        broker.balance = balance
        broker.available = available
        broker.save()


class SchedulerStatusManagement:
    @staticmethod
    def update(scheduler_type, scheduler_name, status, err=None):
        ss, _ = SchedulerStatus.objects.get_or_create(name=f'{scheduler_type}_{scheduler_name}')
        ss.status = status
        if err is not None:
            ss.last_err = err
        ss.save()

    @staticmethod
    def terminate_status(account_name):
        try:
            ss = SchedulerStatus.objects.get(name=account_name)
            if ss is not None and ss.terminate is not None:
                return ss.terminate
        except Exception as e:
            logger.error(f"error query account_name status,account_name::{account_name}")
        else:
            return 0
    @staticmethod
    def terminateUpate(account_name, type):
        try:
            ss = SchedulerStatus.objects.get(name=account_name)
            if ss is not None:
                ss.terminate = type
                ss.save()
        except Exception as e:
            logger.error(f"error query account_name status,account_name::{account_name}")


class TradeRecordManagement:
    @staticmethod
    def add_traderecord( trade: TradeData):
        """"""
        try:
            ctime = dt.strptime(dt.now().strftime('%Y-%m-%d') + " " + trade.time, '%Y-%m-%d %H:%M:%S')
            record = TradeRecord(symbol=trade.symbol, exchange=trade.exchange.value, orderid=trade.orderid,
                                 tradeid=trade.tradeid, direction=trade.direction.value, offset=trade.offset.value,
                                 price=trade.price, volume=trade.volume, datetime=ctime,
                                 account_name=trade.gateway_name)
            record.save()
        except Exception as result:
            logging.info(f'error insert trade record to db：{result}')


class TaskStatusManagement:
    @staticmethod
    def update(name, status, err=None):
        try:
            ss, _ = TaskStatus.objects.get_or_create(name=name)
            ss.status = status
            if err is not None:
                ss.last_err = err
            ss.save()
        except Exception as e:
            logger.warning(f'update [{name}] task status: {e}')

